home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 May / CMCD0504.ISO / Software / Freeware / Programare / dspack / DSPACK231.exe / {app} / Demos / wmvnetwrite / NetWrite.pas next >
Encoding:
Pascal/Delphi Source File  |  2003-01-09  |  22.8 KB  |  775 lines

  1. unit NetWrite;
  2.  
  3. interface
  4. uses Windows, wmf9, SysUtils, activex, Classes;
  5.  
  6. const
  7.   NETWRITE_ASYNC_EVENT    : PCHAR = '{6d12fe9b-d029-4d08-b2eb-92c8cab323c7}';
  8.  
  9. type
  10.  
  11.   TWMFNetWrite = class(TObject, IWMReaderCallback, IWMReaderCallbackAdvanced)
  12.   public
  13.     constructor Create;
  14.  
  15.     destructor  Destroy; override;
  16.     function    Configure(dwPortNum: DWORD; const pwszFile: PWideChar; nMaxClient: cardinal): HRESULT;
  17.     function    WritetoNet: HRESULT;
  18.     function    Init: HRESULT;
  19.  
  20.     //Methods of IWMReaderCallback
  21.  
  22.     function OnSample(dwOutputNum: DWORD; cnsSampleTime, cnsSampleDuration: int64;
  23.                dwFlags: DWORD; pSample: INSSBuffer; pvContext: pointer): HRESULT; stdcall;
  24.     function OnStatus(Status: TWMTSTATUS; hr: HRESULT; dwType: TWMTATTRDATATYPE;
  25.                pValue: PBYTE; pvContext: pointer): HRESULT; stdcall;
  26.  
  27.     //Methhods of IWMReaderCallbackAdvanced
  28.  
  29.     // Receive a sample directly from the ASF. To get this call, the user
  30.     // must register himself to receive samples for a particular stream.
  31.     function OnStreamSample(wStreamNum: WORD; cnsSampleTime, cnsSampleDuration: int64;
  32.                dwFlags: DWORD; pSample: INSSBuffer; pvContext: pointer): HRESULT; stdcall;
  33.  
  34.     // In some cases, the user may want to get callbacks telling what the
  35.     // reader thinks the current time is. This is interesting in 2 cases:
  36.     // - If the ASF has gaps in it; say no audio for 10 seconds. This call
  37.     //   will continue to be called, while OnSample won't be called.
  38.     // - If the user is driving the clock, the reader needs to communicate
  39.     //   back to the user its time, to avoid the user overrunning the reader.
  40.     function OnTime(cnsCurrentTime: int64; pvContext: pointer): HRESULT; stdcall;
  41.  
  42.     // The user can also get callbacks when stream selection occurs.
  43.     function OnStreamSelection(wStreamCount: Word; pStreamNumbers: PWord;
  44.                                pSelections: PWMTSTREAMSELECTION; pvContext: Pointer): HResult; stdcall;
  45.     // Will be called if the user got an async result from their
  46.     // call to SetOutputProps.  The next sample you receive for
  47.     // this output will have these properties.  The contents of the
  48.     // media type after calling SetOutputProps and before receiving
  49.     // an OutputPropsChanged notification are undefined.
  50.     function OnOutputPropsChanged(dwOutputNum: DWORD; pMediaType: PWMMediaType;
  51.                pvContext: pointer): HRESULT; stdcall;
  52.  
  53.  
  54.     // If the user has registered to allocate buffers, this is where he must
  55.     // do it.
  56.     function AllocateForStream(wStreamNum: WORD; cbBuffer: DWORD; out ppBuffer: INSSBuffer;
  57.                pvContext: pointer): HRESULT; stdcall;
  58.  
  59.     function AllocateForOutput(dwOutputNum, cbBuffer: DWORD; out ppBuffer: INSSBuffer;
  60.                pvContext: pointer): HRESULT; stdcall;
  61.  
  62.     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  63.     function _AddRef: Integer; stdcall;
  64.     function _Release: Integer; stdcall;
  65.   private
  66.     function WriteHeader (const pwszName: PWideChar): HRESULT;
  67.     function WriteScript: HRESULT;
  68.   private
  69.     m_hEvent            : THANDLE;
  70.     m_hrAsync           : HRESULT;
  71.     m_qwTime            : Int64;
  72.     m_pWriterAdvanced   : IWMWriterAdvanced;
  73.     m_pReaderAdvanced   : IWMReaderAdvanced;
  74.     m_pReader           : IWMReader;
  75.     m_pWriter           : IWMWriter;
  76.     m_pNetSink          : IWMWriterNetworkSink;
  77.     m_bEOF              : bool;
  78.     m_pReaderHeaderInfo : IWMHeaderInfo;
  79.     m_pWriterHeaderInfo : IWMHeaderInfo;
  80.   public
  81.     function CloseAll: HRESULT;
  82.   end;
  83.  
  84. implementation
  85.  
  86.   constructor TWMFNetWrite.Create;
  87.   begin
  88.     m_pReaderHeaderInfo := nil;
  89.     m_pWriterHeaderInfo := nil;
  90.     m_pWriterAdvanced   := nil;
  91.     m_pReaderAdvanced   := nil;
  92.     m_pReader           := nil;
  93.     m_pWriter           := nil;
  94.     m_pNetSink          := nil;
  95.     m_hEvent            := 0;
  96.     m_bEOF              := false;
  97.     m_qwTime            := 0;
  98.     m_hrAsync           := S_OK;
  99.   end;
  100.  
  101.   destructor TWMFNetWrite.Destroy;
  102.   begin
  103.     CloseAll;
  104.     CloseHandle(m_hEvent);
  105.     m_pWriterAdvanced := nil;
  106.     m_pWriter := nil;
  107.     m_pNetSink := nil;
  108.     m_pReaderAdvanced := nil;
  109.     m_pReader := nil;
  110.     inherited destroy;
  111.   end;
  112.  
  113.   function TWMFNetWrite.Configure(dwPortNum: DWORD; const pwszFile: PWideChar; nMaxClient: cardinal): HRESULT;
  114.   var
  115.     pProfile : IWMProfile;
  116.     pStream  : IWMStreamConfig;
  117.     err, cchURL, dwStreams, i, cInputs : DWORD;
  118.     pwszURL : PWideChar;
  119.     wStreamNumber: WORD;
  120.   begin
  121.     if((dwPortNum = 0) or (pwszFile = nil)) then
  122.     begin
  123.       result := E_INVALIDARG;
  124.       exit;
  125.     end;
  126.  
  127.     if ((m_pWriterAdvanced = nil) or (m_pReaderAdvanced = nil) or (m_pNetSink = nil)) then
  128.     begin
  129.       result := E_UNEXPECTED;
  130.       exit;
  131.     end;
  132.  
  133.     // Create event for handling asynchronous calls
  134.     result   := S_OK;
  135.     pProfile := nil;
  136.     pStream  := nil;
  137.  
  138.     m_hrAsync := S_OK;
  139.  
  140.     m_hEvent := CreateEvent(nil, FALSE, FALSE, NETWRITE_ASYNC_EVENT);
  141.     if (m_hEvent = 0) then
  142.     begin
  143.       err := GetLastError;
  144.       writeln(format('Could not Create Event: (hr=$%x)',[err]));
  145.       result := err;
  146.       exit;
  147.     end;
  148.  
  149.     // Configure the Net Sink
  150.     result := m_pNetSink.SetNetworkProtocol(WMT_PROTOCOL_HTTP);
  151.     if (FAILED(result)) then
  152.     begin
  153.       writeln('Could not Set Network protocol');
  154.       exit;
  155.     end;
  156.  
  157.     result := m_pNetSink.Open(dwPortNum);
  158.     if (FAILED(result)) then
  159.     begin
  160.       writeln(format('Network sink failed to open port no %d',[dwPortNum]));
  161.       exit;
  162.     end; 
  163.  
  164.     cchURL := 0;
  165.  
  166.     result := m_pNetSink.GetHostURL(nil, cchURL);
  167.     if(FAILED(result)) then
  168.     begin
  169.       writeln('Could not get the host URL from IWMWriterNEtworkSink');
  170.       exit;
  171.     end;
  172.      
  173.  
  174.     getmem(pwszURL, cchURL * sizeof(WCHAR));
  175.     if (pwszURL = nil) then
  176.     begin
  177.       result := E_OUTOFMEMORY; // Insufficient Memory
  178.       exit;
  179.     end;
  180.  
  181.     result := m_pNetSink.GetHostURL(pwszURL, cchURL);
  182.     if (FAILED(result)) then
  183.     begin
  184.       writeln('Could not get the host URL from IWMWriterNEtworkSink');
  185.       FreeMem(pwszURL);
  186.       exit;
  187.     end;
  188.  
  189.     writeln('Connect to '+pwszURL);
  190.  //   Sleep(1000);
  191.  
  192.     FreeMem(pwszURL);
  193.  
  194.     // Set the max no of clients that can connect to the port
  195.     result := m_pNetSink.SetMaximumClients(nMaxClient);
  196.     if (FAILED(result)) then
  197.     begin
  198.       writeln('Could not Set maximum clients');
  199.       exit;
  200.     end;
  201.  
  202.     // Add the network sink to the Writer Advanced
  203.     result := m_pWriterAdvanced.AddSink(m_pNetSink);
  204.     if (FAILED(result)) then
  205.     begin
  206.       writeln('Could not Add Sink');
  207.       exit;
  208.     end;   
  209.  
  210.     // Open the requested file
  211.     result := m_pReader.Open(pwszFile, self, nil);
  212.     if (FAILED(result)) then
  213.     begin
  214.       writeln('Could not open file');
  215.       exit;
  216.     end;
  217.  
  218.     // Wait for the open to finish
  219.     WaitForSingleObject(m_hEvent, INFINITE);
  220.     if (FAILED(m_hrAsync)) then
  221.     begin
  222.       writeln(format('Open failed (hr=$%x)',[m_hrAsync]));
  223.       result := m_hrAsync;
  224.       exit;
  225.     end;
  226.  
  227.     // Turn on manual stream selection, so we get all streams.
  228.     result := m_pReaderAdvanced.SetManualStreamSelection(TRUE);
  229.     if (FAILED(result)) then
  230.     begin
  231.       writeln('Failed to set manual stream selection');
  232.       exit;
  233.     end; // 
  234.  
  235.     // Get the profile interface, loop thru all the
  236.     // streams and request the reader to deliver compressed samples
  237.     result := m_pReader.QueryInterface(IID_IWMProfile, pProfile);
  238.     if (FAILED(result)) then
  239.     begin
  240.       writeln('Could not Query for IWMProfile');
  241.       exit;
  242.     end;   
  243.  
  244.  
  245.     dwStreams := 0;
  246.     result := pProfile.GetStreamCount(dwStreams);
  247.     if (FAILED(result)) then
  248.     begin
  249.       writeln(format('GetStreamCount on IWMProfile failed (hr=$%x)', [result]));
  250.       exit;
  251.     end; 
  252.  
  253.     for i := 0 to dwStreams - 1 do
  254.     begin
  255.       result := pProfile.GetStream(i, pStream);
  256.       if (FAILED(result)) then
  257.       begin
  258.         writeln(format('Could not get Stream %d of %d from IWMProfile (hr=0x%08x)',[i,dwStreams,result]));
  259.         break;
  260.       end;
  261.       wStreamNumber := 0;
  262.       //Get the stream number of the current stream
  263.       result := pStream.GetStreamNumber(wStreamNumber);
  264.       if (FAILED(result)) then
  265.       begin
  266.         writeln(format('Could not get stream number from IWMStreamConfig %d of %d (hr=$%x)',
  267.             [i, dwStreams, result]));
  268.         break;
  269.       end;
  270.  
  271.       pStream := nil;
  272.  
  273.       //Set the stream to be recieved in compressed mode
  274.       result := m_pReaderAdvanced.SetReceiveStreamSamples(wStreamNumber, TRUE);
  275.       if (FAILED(result)) then
  276.       begin
  277.         writeln(format('Could not SetReceivedStreamSamples for stream number %d (hr=$%x)',
  278.                        [wStreamNumber, result]));
  279.         break;
  280.       end;
  281.     end;
  282.     pStream := nil;
  283.     if (FAILED(result)) then exit;
  284.  
  285.     // Turn on the user clock
  286.     result := m_pReaderAdvanced.SetUserProvidedClock(TRUE);
  287.     if (FAILED(result)) then
  288.     begin
  289.       writeln(format('SetUserProvidedClock failed (hr=$%x)', [result]));
  290.       exit;
  291.     end; 
  292.  
  293.     // Now set the writers properties
  294.     result := m_pWriter.SetProfile(pProfile);
  295.     if(FAILED(result)) then
  296.     begin
  297.       writeln(format('Could not set profile on IWMWriter (hr=$%x)',[result]));
  298.       exit;
  299.     end;
  300.  
  301.     pProfile := nil;
  302.  
  303.     cInputs := 0;
  304.  
  305.     result := m_pWriter.GetInputCount(cInputs);
  306.     if(FAILED(result)) then
  307.     begin
  308.       writeln(format('Could not get input count from IWMWriter (hr=$%x)',[result]));
  309.       exit;
  310.     end;
  311.  
  312.     for i := 0 to cInputs -1 do
  313.       // Set the input props to NULL to indicate that we don't need a codec
  314.       // because we are writing compressed samples to the port
  315.        m_pWriter.SetInputProps(i, nil);
  316.  
  317.     // Write all the header attributes, which can be set, from the
  318.     // input file to the output port.
  319.     result := WriteHeader(g_wszWMTitle);
  320.     if(FAILED(result)) then exit;
  321.  
  322.     result := WriteHeader( g_wszWMAuthor) ;
  323.     if(FAILED(result)) then exit;
  324.  
  325.     result := WriteHeader( g_wszWMDescription) ;
  326.     if(FAILED(result)) then exit;
  327.  
  328.     result := WriteHeader( g_wszWMRating) ;
  329.     if(FAILED(result)) then exit;
  330.  
  331.     result := WriteHeader( g_wszWMCopyright) ;
  332.     if(FAILED(result)) then exit;
  333.  
  334.     result := WriteHeader( g_wszWMAlbumTitle) ;
  335.     if(FAILED(result)) then exit;
  336.  
  337.     result := WriteHeader( g_wszWMTrack) ;
  338.     if(FAILED(result)) then exit;
  339.  
  340.     result := WriteHeader( g_wszWMPromotionURL) ;
  341.     if(FAILED(result)) then exit;
  342.  
  343.     result := WriteHeader( g_wszWMAlbumCoverURL) ;
  344.     if(FAILED(result)) then exit;
  345.  
  346.     result := WriteHeader( g_wszWMGenre) ;
  347.     if(FAILED(result)) then exit;
  348.  
  349.     result := WriteHeader( g_wszWMYear) ;
  350.     if(FAILED(result)) then exit;
  351.  
  352.     result := WriteHeader( g_wszWMGenreID) ;
  353.     if(FAILED(result)) then exit;
  354.  
  355.     result := WriteHeader( g_wszWMMCDI) ;
  356.     if(FAILED(result)) then exit;
  357.  
  358.     result := WriteHeader( g_wszWMBannerImageType ) ;
  359.     if(FAILED(result)) then exit;
  360.  
  361.     result := WriteHeader( g_wszWMBannerImageData ) ;
  362.     if(FAILED(result)) then exit;
  363.  
  364.     result := WriteHeader( g_wszWMBannerImageURL ) ;
  365.     if(FAILED(result)) then exit;
  366.  
  367.     result := WriteHeader( g_wszWMCopyrightURL ) ;
  368.     if(FAILED(result)) then exit;
  369.  
  370.     //Header has been written. Lets write the script
  371.     result := WriteScript;
  372.   end;
  373.  
  374.   function TWMFNetWrite.WritetoNet: HRESULT;
  375.   begin
  376.     if ((m_hEvent          = 0)   or
  377.         (m_pWriterAdvanced = nil) or
  378.         (m_pReaderAdvanced = nil) or
  379.         (m_pNetSink        = nil)) then
  380.     begin
  381.       result := E_UNEXPECTED;
  382.       exit;
  383.     end;
  384.     // Start Writing
  385.     result := m_pWriter.BeginWriting;
  386.     if (FAILED(result)) then
  387.     begin
  388.       writeln(format('BeginWriting on IWMWriter failed (hr=$%x)',[result]));
  389.       exit;
  390.     end;
  391.  
  392.     result := m_pReader.Start(0, 0, 1.0, nil);
  393.     if (FAILED(result)) then
  394.     begin
  395.       writeln(format('Could not start IWMReader (hr=$%x)',[result]));
  396.       exit;
  397.     end;
  398.  
  399.    // not usefull with Windowed app
  400.   { // Wait for it to finish
  401.     WaitForSingleObject(m_hEvent, INFINITE);
  402.     if (FAILED(m_hrAsync)) then
  403.     begin
  404.       result := m_hrAsync;
  405.       exit; // Net writing failed  ????? not logic for hresult
  406.     end;}
  407.   end;
  408.  
  409.   function TWMFNetWrite.CloseAll: HRESULT;
  410.   begin
  411.  
  412.     // Stop stuff
  413.     if assigned(m_pReader) then
  414.     begin
  415.       result := m_pReader.Stop;
  416.       if (FAILED(result)) then
  417.       begin
  418.         writeln(format('Could not Stop IWMReader (hr=$%x)',[result]));
  419.         exit;
  420.       end; // Could not Stop IWMReader
  421.     end;
  422.  
  423.     if assigned(m_pWriter) then
  424.     begin
  425.       result := m_pWriter.Flush;
  426.       if (FAILED(result)) then
  427.       begin
  428.         writeln(format('Could not Flush on IWMWriter (hr=$%x)',[result]));
  429.         exit;
  430.       end;
  431.       result := m_pWriter.EndWriting;
  432.       if (FAILED(result)) then
  433.       begin
  434.         writeln(format('Could not EndWriting on IWMWriter (hr=$%x)',[result]));
  435.         exit;
  436.       end;
  437.     end;
  438.  
  439.     if assigned(m_pReader) then
  440.     begin
  441.       result := m_pReader.Close;
  442.       if (FAILED(result)) then
  443.       begin
  444.         writeln(format('Could not close the file (hr=$%x)',[result]));
  445.         exit;
  446.       end; 
  447.     end;
  448.  
  449.     if assigned(m_pWriterAdvanced) then
  450.     begin
  451.       result := m_pWriterAdvanced.RemoveSink(m_pNetSink);
  452.       if (FAILED(result)) then
  453.       begin
  454.         writeln(format('Could not remove the Network Sink (hr=$%x)',[result]));
  455.         exit;
  456.       end;
  457.     end;
  458.  
  459.     if assigned(m_pNetSink) then
  460.     begin
  461.       result := m_pNetSink.Close;
  462.       if (FAILED(result)) then
  463.       begin
  464.         writeln(format('Could not close on IWMWriterNetworkSink (hr=$%x)',[result]));
  465.         exit;
  466.       end;
  467.     end;
  468.  
  469.     result := s_ok;
  470.     //Wait for sometime till all the data gets read from the port
  471.     //Sleep(20000);
  472.   end;
  473.  
  474.   function TWMFNetWrite.Init: HRESULT;
  475.   begin
  476.     // Create the reader, writer and network sink.
  477.     result := WMCreateReader( nil, 0, m_pReader);
  478.     if (FAILED(result)) then
  479.     begin
  480.       writeln(format('Could not create reader (hr=$%x)',[result]));
  481.       exit;
  482.     end; 
  483.  
  484.     result := m_pReader.QueryInterface(IID_IWMReaderAdvanced, m_pReaderAdvanced);
  485.     if (FAILED(result)) then
  486.     begin
  487.       writeln(format('Could not QI for IWMReaderAdvanced (hr=$%x)',[result]));
  488.       exit;
  489.     end;
  490.  
  491.     result := WMCreateWriter(nil, m_pWriter);
  492.     if (FAILED(result)) then
  493.     begin
  494.       writeln(format('Could not create Writer (hr=$%x)',[result]));
  495.       exit;
  496.     end;
  497.  
  498.     result := m_pWriter.QueryInterface(IID_IWMWriterAdvanced, m_pWriterAdvanced);
  499.     if (FAILED(result)) then
  500.     begin
  501.       writeln(format('Could not QI for IWMWriterAdvanced (hr=$%x)',[result]));
  502.       exit;
  503.     end;  
  504.  
  505.     result := WMCreateWriterNetworkSink(m_pNetSink);
  506.     if (FAILED(result)) then
  507.     begin
  508.       writeln(format('Could not create Writer Network Sink (hr=$%x)',[result]));
  509.       exit;
  510.     end; 
  511.  
  512.     result := m_pReader.QueryInterface(IID_IWMHeaderInfo, m_pReaderHeaderInfo);
  513.     if (FAILED(result)) then
  514.     begin
  515.       writeln(format('Could not QI for IWMHeaderInfo (hr=$%x)',[result]));
  516.       exit;
  517.     end;
  518.  
  519.     result := m_pWriter.QueryInterface(IID_IWMHeaderInfo, m_pWriterHeaderInfo);
  520.     if (FAILED(result)) then
  521.     begin
  522.       writeln(format('Could not QI for IWMHeaderInfo (hr=$%x)',[result]));
  523.       exit;
  524.     end; 
  525.   end;
  526.  
  527.   function TWMFNetWrite.OnSample(dwOutputNum: DWORD; cnsSampleTime, cnsSampleDuration: int64;
  528.              dwFlags: DWORD; pSample: INSSBuffer; pvContext: pointer): HRESULT;
  529.   begin
  530.     if (m_hEvent <> 0) then
  531.     begin
  532.       //The samples are expected in OnStreamSample
  533.       writeln('Error: Received a decompressed sample from the reader');
  534.       m_hrAsync := E_UNEXPECTED;
  535.       SetEvent(m_hEvent);
  536.     end;
  537.     result := S_OK;
  538.   end;
  539.  
  540.   function TWMFNetWrite.OnStatus(Status: TWMTSTATUS; hr: HRESULT; dwType: TWMTATTRDATATYPE;
  541.              pValue: PBYTE; pvContext: pointer): HRESULT;
  542.   begin
  543.     case Status of
  544.       WMT_OPENED:
  545.         begin
  546.           m_hrAsync := hr;
  547.           SetEvent(m_hEvent);
  548.         end;
  549.       WMT_END_OF_FILE:
  550.         begin
  551.           m_bEOF := true;
  552.           writeln('EndOfStream detected in reader');
  553.           m_hrAsync := hr;
  554.           SetEvent(m_hEvent);
  555.         end;
  556.       WMT_STARTED:
  557.         begin
  558.           //Ask for the specific duration of the stream to be delivered
  559.           m_qwTime := 0;
  560.           m_qwTime := m_qwTime + (1000 * 10000);
  561.           hr := m_pReaderAdvanced.DeliverTime(m_qwTime);
  562.           assert(SUCCEEDED(hr));
  563.         end;
  564.       end;
  565.       result :=  S_OK;
  566.   end;
  567.  
  568.   function TWMFNetWrite.OnStreamSample(wStreamNum: WORD; cnsSampleTime, cnsSampleDuration: int64;
  569.                dwFlags: DWORD; pSample: INSSBuffer; pvContext: pointer): HRESULT;
  570.   begin
  571.      writeln(format('StreamSample: num=%d, time=%d, duration=%d, flags=%d',
  572.                      [wStreamNum, cnsSampleTime, cnsSampleDuration, dwFlags]));
  573.     //We've got a sample. Lets write it
  574.     m_pWriterAdvanced.WriteStreamSample( wStreamNum, cnsSampleTime, 0, cnsSampleDuration, dwFlags, pSample);
  575.     result := S_OK;
  576.   end;
  577.  
  578.   function TWMFNetWrite.OnTime(cnsCurrentTime: int64; pvContext: pointer): HRESULT;
  579.   begin
  580.     //Keep asking for the specific duration of the stream till EOF
  581.     if( not m_bEOF) then
  582.     begin
  583.       m_qwTime := m_qwTime + 10000000;
  584.       m_pReaderAdvanced.DeliverTime(m_qwTime);
  585.     end;
  586.     result := S_OK;
  587.   end;
  588.  
  589.   function TWMFNetWrite.OnStreamSelection( wStreamCount: Word; pStreamNumbers: PWORD;
  590.                pSelections: PWMTSTREAMSELECTION; pvContext: pointer): HRESULT;
  591.   begin
  592.     result := S_OK;
  593.   end;
  594.  
  595.   function TWMFNetWrite.OnOutputPropsChanged(dwOutputNum: DWORD; pMediaType: PWMMEDIATYPE;
  596.                pvContext: pointer): HRESULT;
  597.   begin
  598.     result := S_OK;
  599.   end;
  600.  
  601.   function TWMFNetWrite.AllocateForStream(wStreamNum: WORD; cbBuffer: DWORD; out ppBuffer: INSSBuffer;
  602.              pvContext: pointer): HRESULT;
  603.   begin
  604.     result := E_NOTIMPL;
  605.   end;
  606.  
  607.   function TWMFNetWrite.AllocateForOutput(dwOutputNum, cbBuffer: DWORD; out ppBuffer: INSSBuffer;
  608.              pvContext: pointer): HRESULT;
  609.   begin
  610.     result := E_NOTIMPL;
  611.   end;
  612.  
  613.   function TWMFNetWrite.WriteHeader (const pwszName: PWideChar): HRESULT;
  614.   var
  615.     nstreamNum : WORD;
  616.     cbLength   : WORD;
  617.     _type      : TWMTAttrDataType;
  618.     hr         : HRESULT;
  619.     pValue     : PBYTE;
  620.   begin
  621.     nstreamNum := 0;
  622.     cbLength   := 0;
  623.     result     := S_OK;
  624.     pValue     := nil;
  625.  
  626.     // Get the no of bytes to be allocated for pValue
  627.     result := m_pReaderHeaderInfo.GetAttributeByName(nstreamNum, pwszName, _type, nil, cbLength);
  628.     if (FAILED(result) and (result <> longint(ASF_E_NOTFOUND))) then
  629.     begin
  630.       writeln(format('GetAttributeByName failed for Attribute name %s (hr=$%x)',[pwszName, result]));
  631.       exit;
  632.     end;
  633.  
  634.     if ((cbLength = 0) or (result = longint(ASF_E_NOTFOUND))) then
  635.     begin
  636.       result := S_OK;
  637.       exit;
  638.     end;
  639.  
  640.     getmem(pValue, cbLength);
  641.     if (pValue = nil) then
  642.     begin
  643.       writeln(format('Unable to allocate memory for the Attribute name %s', [pwszName]));
  644.       result := E_OUTOFMEMORY; 
  645.       exit;
  646.     end;
  647.  
  648.     //Dummy do-while loop
  649.     repeat
  650.       // Get the value
  651.       hr := m_pReaderHeaderInfo.GetAttributeByName(nstreamNum, pwszName, _type, pValue, cbLength);
  652.       if (FAILED(hr)) then
  653.       begin
  654.         writeln(format('GetAttributeByName failed for Attribute name %s (hr=$%x)', [pwszName, hr]));
  655.         break;
  656.       end; 
  657.  
  658.       // Set the attribute
  659.       hr := m_pWriterHeaderInfo.SetAttribute(nstreamNum, pwszName, _type, pValue, cbLength);
  660.       if (FAILED(hr)) then
  661.       begin
  662.         writeln(format('SetAttribute failed for Attribute name %s (hr=$%x)',[pwszName, hr]));
  663.         break;
  664.       end; 
  665.     until (FALSE);
  666.  
  667.     freemem(pValue);
  668.     pValue := nil;
  669.     result := hr;
  670.   end;
  671.  
  672.   function TWMFNetWrite.WriteScript: HRESULT;
  673.   var
  674.     hr            : HRESULT;
  675.     pwszCommand   : PWideChar;
  676.     pwszType      : PWideChar;
  677.     cnsScriptTime : int64;
  678.     cScript       : WORD;
  679.     cchTypeLen    : WORD;
  680.     cchCommandLen : WORD;
  681.     i             : integer;
  682.   begin
  683.     hr            := S_OK;
  684.     pwszCommand   := nil;
  685.     pwszType      := nil;
  686.     cnsScriptTime := 0;
  687.     cScript       := 0;
  688.     cchTypeLen    := 0;
  689.     cchCommandLen := 0;
  690.  
  691.  
  692.     result := m_pReaderHeaderInfo.GetScriptCount(cScript);
  693.     if (FAILED(result)) then
  694.     begin
  695.       writeln(format('GetScriptCount failed (hr=$%x)',[result]));
  696.       exit;
  697.     end;
  698.  
  699.     for i := 0 to cScript - 1 do
  700.     begin
  701.       // Get the memory reqd for this script
  702.       hr := m_pReaderHeaderInfo.GetScript(i, nil, cchTypeLen, nil, cchCommandLen, cnsScriptTime);
  703.       if (FAILED(hr)) then
  704.       begin
  705.         writeln(format('GetScript failed for Script no %d (hr=$%x)',[i, hr]));
  706.         break;
  707.       end;
  708.  
  709.       getmem(pwszType, cchTypeLen * sizeof(WORD));
  710.       getmem(pwszCommand, cchCommandLen * sizeof(WORD));
  711.  
  712.       if ((pwszType = nil) or (pwszCommand = nil)) then
  713.       begin
  714.         hr := E_OUTOFMEMORY;
  715.         break;
  716.       end;
  717.  
  718.       // Now, get the script
  719.       hr := m_pReaderHeaderInfo.GetScript(i, pwszType, cchTypeLen, pwszCommand, cchCommandLen, cnsScriptTime);
  720.       if (FAILED(hr)) then
  721.       begin
  722.         writeln(format('GetScript failed for Script no %d (hr=$%x)', [i, hr]));
  723.         break;
  724.       end;  // GetScript failed for Script no %d
  725.  
  726.       // Add the script to the writer
  727.       hr := m_pWriterHeaderInfo.AddScript(pwszType, pwszCommand, cnsScriptTime);
  728.       if (FAILED(hr)) then
  729.       begin
  730.         Writeln(format('AddScript failed for Script no %d (hr=$%x)', [i, hr]));
  731.         break;
  732.       end;
  733.  
  734.       if pwszType <> nil then freemem(pwszType);
  735.       if pwszCommand <> nil then freemem(pwszCommand);
  736.       pwszType    := nil;
  737.       pwszCommand := nil;
  738.       cchTypeLen    := 0 ;
  739.       cchCommandLen := 0 ;
  740.     end;
  741.  
  742.     if pwszType <> nil then freemem(pwszType);
  743.     if pwszCommand <> nil then freemem(pwszCommand);
  744.     pwszType    := nil;
  745.     pwszCommand := nil;
  746.     result := hr;
  747.   end;
  748.  
  749.   function TWMFNetWrite.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  750.   begin
  751.     if IsEqualGUID(IID, IID_IWMReaderCallback) then
  752.        IWMReaderCallback(Obj) := self
  753.     else
  754.       if IsEQualGUID(IID, IID_IWMReaderCallbackAdvanced) then
  755.         IWMReaderCallbackAdvanced(obj) := self
  756.       else
  757.       begin
  758.         result := E_NOINTERFACE;
  759.         exit;
  760.       end;
  761.     result := S_OK;
  762.   end;
  763.  
  764.   function TWMFNetWrite._AddRef: Integer; stdcall;
  765.   begin
  766.     result := 1;
  767.   end;
  768.  
  769.   function TWMFNetWrite._Release: Integer; stdcall;
  770.   begin
  771.     result := 1;
  772.   end;
  773.  
  774. end.
  775.